// ====================CardGameManager====================

/**
 * 卡牌游戏管理器
 * 管理卡牌对局状态的静态类
 */
class CardGameManager {

    static _playerTurn = true;
    static _phase = null;
    static _phaseMap = {};
    static _usingCard = null;
    static _target = null;
    static _cardAction = [];

    static _energy = 0;
    static _maxEnergy = 0;

    static _updateCount = 0;
    static _gameEnd = false;

    static deck = [];
    static cemetery = [];

    static cardGameInit() {
        this._playerTurn = true;
        this.deck = $gameParty.deckLists().disarrange().map(cardId => {
            return new Game_Card(cardId)
        });
        // 测试用固定卡组
        // this.deck = [12, 13, 14, 15, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20].map(cardId => {
        //     return new Game_Card(cardId);
        // });
        this._phase = null;
        this._usingCard = null;
        this._target = null;
        this._cardAction = [];
        this._energy = 0;
        this._maxEnergy = SDS_CARD_PLUGIN_PARAM.gameOption.maxEnergy;
        this._updateCount = 0;
        this._gameEnd = false;
        this.cemetery = [];
        this.cardTurnCount = 0;
        this.initGamePhase();
        $gameSystem.onBattleStart();
        $gameParty.onBattleStart(false);
        $gameTroop.onBattleStart(false);
    }

    static get energy() {
        return this._energy;
    }

    static set energy(value) {
        this._energy = Math.min(Math.max((value), 0), this._maxEnergy);
    }

    static get maxEnergy() {
        return this._maxEnergy;
    }

    static set maxEnergy(value) {
        this._maxEnergy = Math.max(value, 0);
    }

    static get usingCard() {
        return this._usingCard;
    }

    /**
     * 是否是卡牌游戏
     * @returns {boolean}
     */
    static isCardGame() {
        return true;
    }

    /**
     * 初始化卡牌游戏阶段
     */
    static initGamePhase() {
        const map = this._phaseMap;
        map.gameStart = new CardPhase_GameStart();
        map.turn = new CardPhase_Turn();
        map.turnEnd = new CardPhase_TurnEnd();
        map.gameEnd = new CardPhase_GameEnd();
    }

    static setup() {
        this.changePhase("gameStart")
    }

    /**
     * 卡牌战斗角色
     */
    static cardBattler() {
        return $gameActors.actor(SDS_CARD_PLUGIN_PARAM.gameOption.cardBattler);
    }

    /**
     * 手牌精灵
     */
    static handCardSprite() {
        return this._cardPanel.handCardSprite();
    }

    /**
     * 手牌数量
     */
    static handCardAmount() {
        return this._cardPanel.handCardObject().length;
    }

    /**
     * 发牌
     * @param {Number} amount 数量
     */
    static deal(amount) {
        // 处理牌库数量不足时，从墓地补充卡牌
        if (this.deck.length < amount) {
            this.deck.push(...this.cemetery.disarrange());
            this.cemetery = [];
        }
        const handCardAmount = this.handCardAmount();
        const cards = [];
        for (let i = 0; i < amount; i++) {
            if (handCardAmount >= SDS_CARD_PLUGIN_PARAM.gameOption.maxHandCard) break;
            const card = this.deck.shift();
            cards.push(card);
        }
        this._cardPanel.draw(cards, CardGameManager.deckPosition);
    }

    static deckRetrieve(cards) {
        if (cards.constructor.name === "Game_Card") {
            this.deck.remove(cards);
            this._cardPanel.draw(cards, CardGameManager.deckPosition);
        } else {
            for (const card of cards) {
                this.deck.remove(card);
                this._cardPanel.draw(card, CardGameManager.deckPosition);
            }
        }
    }

    static cemeteryRetrieve(cards) {
        if (cards.constructor.name === "Game_Card") {
            this.cemetery.remove(cards);
            this._cardPanel.draw(cards, CardGameManager.cemeteryPosition);
        } else {
            for (const card of cards) {
                this.cemetery.remove(card);
                this._cardPanel.draw(card, CardGameManager.cemeteryPosition);
            }
        }
    }

    /**
     * 请求出牌
     * @param {Sprite_HandCard} user 使用的牌
     * @param {number|null} target 目标
     */
    static requestPlayCard(user, target) {
        const card = user.object();
        const result = this.canPlayCard(card, target);
        if (result) {
            this.playCard(card, target);
            user.recycle();
        }
    }

    /**
     * 出牌
     * @param {Game_Card} card 卡牌对象
     * @param {number} target 目标
     * @returns {Boolean} 是否成功打出
     */
    static playCard(card, target) {
        const cost = card.cost();
        const armor = card.armor();
        // 增加护甲
        $gameParty.battleMembers()[0].gainArmor(armor);
        // 扣除能量
        CardGameManager.energy -= cost;
        // 设置目标
        card.setTarget(target);
        // 解除锁定
        card.unlock();
        // 投入墓地
        this.cemetery.push(card);
        this._usingCard = card;
    }

    /**
     * 卡牌结束
     */
    static cardEnd() {
        this._usingCard = null;
    }

    /**
     * 制作卡牌行动
     */
    static makeCardAction() {
        const card = this._usingCard;
        const skillId = card.skillId();
        const actor = $gameParty.battleMembers()[0];
        const action = new Game_Action(actor);
        const animationId = card.animationId();
        const targetIndex = card.target();
        let animation = null;
        action.setSkill(skillId);
        action.setTarget(targetIndex);
        const targets = action.makeTargets();
        if (animationId) {
            const previous = this._cardAction[this._cardAction.length - 1]?.animation ?? null;
            animation = new Sprite_Animation();
            animation.setup(this.makeAnimationTarget(targets), $dataAnimations[animationId], false, 8, previous);
            this._animationContainer.addChild(animation);
        }
        this._cardAction.push({action, animation, targets})
    }

    /**
     * 制作怪物行动
     */
    static makeEnemyAction() {
        const enemies = $gameTroop.aliveMembers();
        // TODO 在没有自己的action处理前临时
        let delay = 8;
        for (const enemy of enemies) {
            const action = enemy.currentAction();
            if (!action?.item()) continue;
            const animationId = action.animationId();
            let animation = null;
            const targets = action.makeTargets();

            if (!!animationId) {
                const previous = this._cardAction[this._cardAction.length - 1]?.animation ?? null;
                animation = new Sprite_Animation();
                animation.setup(this.makeAnimationTarget(targets), $dataAnimations[animationId], false, delay, previous);
                this._animationContainer.addChild(animation);
            }
            this._cardAction.push({action, animation, targets});
            delay += 20;
        }
    }

    static makeAnimationTarget(targets) {
        const sprites = SceneManager._scene.battlerSprite();
        return sprites.filter(sprite => {
            return targets.includes(sprite.battler());
        });
    }

    /**
     * 开始卡牌游戏新的回合
     */
    static cardTurnStart() {
        this._playerTurn = true;
        this.cardTurnCount++;
        // 清空自身护盾
        $gameParty.battleMembers()[0].clearArmor();
        // 发2张牌
        this.deal(SDS_CARD_PLUGIN_PARAM.gameOption.turnDrawCardAmount);
        // 恢复能量
        this.energy = SDS_CARD_PLUGIN_PARAM.gameOption.energyRecovery;
        // 制作怪物行动
        $gameTroop.makeActions();
        // 刷新怪物行动预告
        const sprites = SceneManager._scene.enemySprite();
        for (const sprite of sprites) {
            sprite.refreshProphesy();
        }
        // 回合开始清空玩家护甲
        $gameParty.battleMembers()[0].clearArmor();
    }

    /**
     * 玩家回合结束
     */
    static cardTurnEnd() {
        if (this.isBattlerActioning() || this.isEffecting() || this.isAnyWindowOpen()) {
            SoundManager.playCancel();
            return;
        }
        const cards = this._cardPanel.abandonAllHandCard();
        this.cemetery.push(...cards);
        this._playerTurn = false;
        // 回合结束清空怪物护甲
        for (const enemy of $gameTroop.members()) {
            enemy.clearArmor();
        }
    }

    /**
     * 设置手牌面板
     */
    static setCardPanel(cardPanel) {
        this._cardPanel = cardPanel;
    }

    /**
     * 设置卡牌效果面板
     */
    static setCardEffectPanel(cardEffectPanel) {
        this._cardEffectPanel = cardEffectPanel;
    }

    /**
     * 设置状态精灵
     */
    static setCemeterySprite(stateSprite) {
        this._stateSprite = stateSprite;
    }

    /**
     * 设置动画容器
     */
    static setAnimationContainer(animationContainer) {
        this._animationContainer = animationContainer;
    }

    /**
     * 设置牌堆精灵
     */
    // static setDeckSprite(deckSprite) {
    //     this._deckSprite = deckSprite;
    // }

    /**
     * 设置卡牌展示窗口
     * @param displayWindow
     */
    static setDisplayWindow(displayWindow) {
        this._displayWindow = displayWindow;
    }

    /**
     * 设置奖励窗口
     * @param window
     */
    static setRewardWindow(window) {
        this._rewardWindow = window;
    }

    /**
     * 设置提示窗口
     * @param window
     */
    static setTipWindow(window) {
        this._tipWindow = window;
    }

    /**
     * 清理
     */
    static clear() {
        this._cardPanel = null;
        this._cardEffectPanel = null;
        this._animationContainer = null;
        this._displayWindow = null;
        this._rewardWindow = null;
        this._tipWindow = null;
        this.deck = [];
        this.cemetery = [];
        this.cardTurnCount = -1;
    }

    /**
     * 提示
     * @param text
     */
    static tip(text) {
        this._tipWindow.pop(text)
    }

    /**
     * 展示牌库
     */
    static displayDeck() {
        const text = "牌库(随机顺序)";
        const list = [...CardGameManager.deck].disarrange();
        this._displayWindow.open({text, list});
    }

    /**
     * 展示墓地
     */
    static displayCemetery() {
        const text = "墓地";
        const list = [...CardGameManager.cemetery]
        this._displayWindow.open({text, list});
    }

    /**
     * 展示奖励卡牌选择
     */
    static displayRewardCard(data, callback) {
        this._displayWindow.startSelect(data, callback);
    }

    /**
     * 结算奖励
     */
    static settlement(data) {
        this._rewardWindow.open(data);
    }

    /**
     * 当前是否可以打出牌
     * @param {Game_Card} card 卡牌对象
     * @param {number} targetIndex 目标索引
     */
    static canPlayCard(card, targetIndex) {
        // 当前是否是玩家回合
        if (!this._playerTurn) return false;
        // 是否有卡牌效果进行中
        if (!!this.usingCard) return false;
        // 牌是否被锁定
        if (card.isLock()) return false;
        // 检查能量是否足够
        const cardCost = card.cost();
        if (this.energy < cardCost) return false;
        // 是否满足自定义条件
        if (!card.meetRequirement()) return false;
        // 检查是否需要目标
        const skillId = card.skillId();
        const skill = $dataSkills[skillId];
        if ([1, 7, 9, 12].includes(skill.scope)) {
            if (targetIndex >= 0 || $gameTroop.aliveMembers().length <= 1) {
                return true;
            } else {
                return false;
            }
        }
        return true;
    }

    static changePhase(phaseName) {
        const phase = this._phaseMap[phaseName]
        if (!phase) return;
        if (this._phase) {
            this._phase.onExit();
        }
        this._phase = phase;
        this._phase.onEnter();
    }

    /**
     * 是否有单位行动中
     */
    static isBattlerActioning() {
        return this._cardAction.length > 0;
    }

    /**
     * 是否正在卡牌效果中
     */
    static isEffecting() {
        return this._cardEffectPanel.visible;
    }

    /**
     * 是否任何窗口打卡
     */
    static isAnyWindowOpen() {
        return this._displayWindow.visible || this._rewardWindow.visible;
    }

    /**
     * 是否回合结束
     */
    static isTurnEnd() {
        return this._playerTurn === false;
    }

    /**
     * 更新阶段
     */
    static updatePhase() {
        if (this.canUpdatePhase()) {
            this._phase.onUpdate();
        }
        this.updateCardAction();
        this.updateBattleEnd();
    }

    /**
     * 是否可以更新阶段
     * @returns {*}
     */
    static canUpdatePhase() {
        return !!this._phase;
    }

    static updateCardAction() {
        for (const cardAction of this._cardAction) {
            // TODO 伤害弹出消失临时解决方案
            let delay = 0;
            const {action, animation, targets} = cardAction;
            if (!animation || !animation.isPlaying()) {
                for (const target of targets) {
                    setTimeout(() => {
                        action.apply(target);
                        target.performanceCardActionResults();
                    }, delay)
                    delay += 20
                }
                if (!!animation) {
                    animation.destroy();
                    this._animationContainer.removeChild(animation);
                }
                this._cardAction.remove(cardAction);
            }
        }
    }

    /**
     * 更新战斗结束
     */
    static updateBattleEnd() {
        if (this._gameEnd) return;
        if (this._updateCount > 0) {
            this._updateCount--;
            return;
        }
        this._updateCount = 10;
        if ($gameTroop.aliveMembers().length <= 0) {
            this.changePhase("gameEnd");
            this._gameEnd = true;
        } else if ($gameParty.aliveMembers().length <= 0) {
            SceneManager.goto(Scene_Gameover);
        }
    }
}